package com.bizmda.bizsip.source.api;

import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.bizmda.bizsip.common.*;
import com.bizmda.bizsip.source.config.SourceConfiguration;
import com.bizmda.log.trace.MDCTraceUtils;
import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.ConnectionPoolTimeoutException;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.lang.reflect.Method;
import java.net.SocketTimeoutException;

/**
 * @author shizhengye
 */
@Slf4j
public class AppServiceClientMethod {
    private final Method method;
    private final AppServiceClientProxy<?> appServiceClientProxy;

    private final RestTemplate restTemplate = SpringUtil.getBean(RestTemplate.class);
    private final SourceConfiguration sourceConfiguration = SpringUtil.getBean(SourceConfiguration.class);

    public AppServiceClientMethod(Method method, AppServiceClientProxy<?> appServiceClientProxy) {
        this.method = method;
        this.appServiceClientProxy = appServiceClientProxy;
    }

    public Object execute(Object[] args) throws BizException {
        BizMessage<JSONObject> outMessage = this.doBizService(this.appServiceClientProxy.getBizServiceId(), args);
        if (outMessage.getCode() != 0) {
            throw new BizException(outMessage);
        }
        if (this.appServiceClientProxy.getMapperInterface().equals(BizMessageInterface.class)) {
            return outMessage;
        }
        JSONObject jsonObject = new JSONObject(outMessage.getData());
        Object result = jsonObject.get("result");
        return BizTools.convertMethodReturnJson2Bean(method,result);
    }

    private BizMessage<JSONObject> doBizService(String bizServiceId, Object[] args) throws BizException {
        JSONObject jsonObject = new JSONObject();
        if (this.appServiceClientProxy.getMapperInterface().equals(BizMessageInterface.class)) {
            if (args[0] instanceof JSONObject) {
                jsonObject = (JSONObject) args[0];
            } else {
                jsonObject = JSONUtil.parseObj(args[0]);
            }
        } else {
            jsonObject.set("className", appServiceClientProxy.getMapperInterface().getName());
            jsonObject.set("methodName", this.method.getName());
            jsonObject.set("params", JSONUtil.parseArray(args));
            JSONObject parametersTypes = BizTools.getParamtersTypesJsonObject(this.method,args);
            if (parametersTypes.size() > 0) {
                jsonObject.set("paramsTypes",parametersTypes);
            }
        }
        HttpHeaders header = new HttpHeaders();
        header.add(BizConstant.APP_SERVICE_SERVICE_ID, bizServiceId);
        if (SourceClientFactory.getTraceId() != null) {
            header.add(BizConstant.APP_SERVICE_TRACE_ID,SourceClientFactory.getTraceId());
        }
        HttpEntity<JSONObject> httpEntity = new HttpEntity<>(jsonObject, header);

        log.debug("调用App服务: {}",bizServiceId);
        log.trace("调用App服务请求报文:\n{}",BizUtils.buildJsonLog(jsonObject));
        BizMessage<JSONObject> outMessage = null;
        try {
            outMessage = this.restTemplate.postForObject(this.sourceConfiguration.getIntegratorUrl(), httpEntity, BizMessage.class);
        } catch (Exception e) {
            if ((e.getCause() instanceof SocketTimeoutException)
                || (e.getCause() instanceof ConnectTimeoutException)) {
                throw new BizException(BizResultEnum.OTHER_SERVICE_TIMEOUT,e);
            }
            throw e;
        }
        if (outMessage == null) {
            log.error("App服务返回为null");
            throw new BizException(BizResultEnum.SOURCE_RETURN_NULL);
        }
        MDCTraceUtils.putTraceId(outMessage.getTraceId());
        if (outMessage.getCode() == 0) {
            outMessage = BizMessage.buildSuccessMessage(outMessage, JSONUtil.parseObj(outMessage.getData()));
            log.trace("App服务响应报文:\n{}", BizUtils.buildBizMessageLog(outMessage));
        }
        else {
            log.error("App服务返回错误:{}-{}\n{}", outMessage.getCode(),
                    outMessage.getMessage(),outMessage.getExtMessage());
        }
        BizTools.bizMessageThreadLocal.set(outMessage);
        return outMessage;
    }

}
